package com.ccnf.service.impl;

import com.ccnf.core.utils.SystemClock;
import com.ccnf.service.TokenService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * iss: jwt签发者
 * sub: 面向的用户(jwt所面向的用户)
 * aud: 接收jwt的一方
 * exp: 过期时间戳(jwt的过期时间，这个过期时间必须要大于签发时间)
 * nbf: 定义在什么时间之前，该jwt都是不可用的.
 * iat: jwt的签发时间
 * jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。
 */
@Service
public class TokenServiceImpl implements TokenService {
    @Value("${jwt.secretKey}")
    private String secretKey;
    @Value("${jwt.ttlMillis}")
    private Long ttlMillis;

    @Override
    public String createTokenByJJwt(Long userId, Long expoId, String channelCode) {
        // 生成JWT的时间
        long nowMillis = SystemClock.milli();
        Date now = new Date(nowMillis);
        // 创建payload的私有声明（根据特定的业务需要添加，如果要拿这个做验证，一般是需要和jwt的接收方提前沟通好验证方式的）
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("expoId", expoId);
        claims.put("channelCode", channelCode);
        Key key  = Keys.hmacShaKeyFor(secretKey.getBytes());
        String token = Jwts.builder()
//                .setSubject("Joe")
                .signWith(key, SignatureAlgorithm.HS256)
                .setClaims(claims)// 如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                .setIssuedAt(now)// iat: jwt的签发时间
//                .setIssuer("admin")// issuer：jwt签发人
//                .setHeaderParam("kid", IdWorker.getIdStr())
                .setHeaderParam("typ", "JWT")
//                .setId(IdWorker.getIdStr())// 设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                .setExpiration(new Date(SystemClock.milli() + ttlMillis))
                .compact();
        return token;
    }

    @Override
    public Claims verifyJwtByJJwt(String token) {
        Key key = Keys.hmacShaKeyFor(secretKey.getBytes());  //签名秘钥，和生成的签名的秘钥一模一样
        Claims claims = Jwts.parser()  //得到DefaultJwtParser
                .setSigningKey(key)         //设置签名的秘钥
                .parseClaimsJws(token).getBody();//设置需要解析的jwt
        return claims;
    }
}